﻿#include "customChart.h"


CustomChart::CustomChart(){

}


QVariantMap CustomChart::getCurveInfo(){


    QTime timer;
    timer.start();

    QVariantMap res;
    res["MinX"] = _minX;
    res["MinY"] = _minY;
    res["MaxX"] = _maxX;
    res["MaxY"] = _maxY;
    QVariantList curveList;
    foreach(stCurve curve, _curveList){
        QVariantMap curveMap;

        // QVector<QPointF>转换为QVariantList<QVariantMap>
        QVariantList normPointList;
        foreach(QPointF point, curve.normPointList){
            normPointList.push_back(point.x());
            normPointList.push_back(point.y());
        }
        QVariantList bezierPointList;
        foreach(QPointF point, curve.bezierPointList){
            bezierPointList.push_back(point.x());
            bezierPointList.push_back(point.y());
        }
        curveMap["NormPointList"] = normPointList;
        curveMap["BezierPointList"] = bezierPointList;
        curveMap["LineWidth"] = curve.lineWidth;
        curveMap["CurveType"] = (int)curve.curveType;
        curveMap["Color"] = curve.color;
        curveList.push_back(curveMap);
    }
    res["CurveList"] = curveList;

//    qDebug() << "CPP-GenerateVariantMap" << QString::number(timer.elapsed()) + "ms";
    return res;
}

void CustomChart::clear(){
    _curveList.clear();
}

void CustomChart::refresh(){



    calculate();
    emit sigRefresh();
}

void CustomChart::appendCurve(QString name, QVector<QPointF> pointList, QColor color, int lineWidth, enCurveType type){
    stCurve curve;
    curve.pointList = pointList;
    curve.color = color;
    curve.curveType = type;
    curve.lineWidth = lineWidth;

    curve.maxX = _defaultMaxX;
    curve.maxY = _defaultMaxY;
    curve.minX = _defaultMinX;
    curve.minY = _defaultMinY;
    foreach(QPointF point, pointList){
        curve.maxX = std::max(curve.maxX, point.x());
        curve.maxY = std::max(curve.maxY, point.y());
        curve.minX = std::min(curve.minX, point.x());
        curve.minY = std::min(curve.minY, point.y());
    }
    _curveList[name] = curve;
}

void CustomChart::printCurveInfo(){
    QString str = "CURVE_LIST: { ";
    foreach(QString name, _curveList.keys()){
        str.append(name + " ");
    }
    str.append("}");
    qDebug() << str;
}

void CustomChart::calculate(){

    QTime timer;
    timer.start();

    calRange();
    calNorm();
    calBezier();

//    qDebug() << "CPP-CalculateTime:" << QString::number(timer.elapsed()) + "ms";

}

void CustomChart::calRange(){
    _maxX = _defaultMaxX;
    _maxY = _defaultMaxY;
    _minX = _defaultMinX;
    _minY = _defaultMinY;
    foreach(stCurve curve, _curveList){
        _maxX = std::max(_maxX, curve.maxX);
        _minX = std::min(_minX, curve.minX);
        _maxY = std::max(_maxY, curve.maxY);
        _minY = std::min(_minY, curve.minY);
    }

    _maxY = calCeilRange(_maxY);

    if(_isFixedMaxX)    { _maxX = _fixedMaxX; }
    if(_isFixedMinX)    { _minX = _fixedMinX; }
    if(_isFixedMaxY)    { _maxY = _fixedMaxY; }
    if(_isFixedMinY)    { _minY = _fixedMinY; }
}

void CustomChart::calNorm(){
    for(auto iter = _curveList.begin(); iter != _curveList.end(); iter ++){
        stCurve &curve = iter.value();
        curve.normPointList.clear();
        foreach(QPointF point, curve.pointList){
            curve.normPointList.push_back(QPointF((point.x()-_minX)/(_maxX-_minX),
                                                  (point.y()-_minY)/(_maxY-_minY)));
        }
    }
}

void CustomChart::calBezier(){
    QPointF ps, pe;          // 临时变量
    double dx, dy, blen;     // 临时变量
    double bezierSpline = 0.3;  // 参数0~1，贝塞尔曲线弯曲程度
    for(auto iter = _curveList.begin(); iter != _curveList.end(); iter ++){
        stCurve &curve = iter.value();
        curve.bezierPointList.clear();

        if(curve.normPointList.size() <= 1){
            continue;       // 曲线长度小于等于1时无贝塞尔曲线
        }
        for(int i = 0; i < curve.normPointList.size() - 1; i ++){
            if(i == 0){
                curve.bezierPointList.push_back(curve.normPointList[0]);
                continue;
            }
            // 两个点之间的斜率
            ps = curve.normPointList[i-1];  pe = curve.normPointList[i+1];
            dx = pe.x() - ps.x();           dy = pe.y() - ps.y();
            blen = std::sqrt(dy*dy+dx*dx);
            dx = dx * bezierSpline;
            dy = dy * bezierSpline;
            curve.bezierPointList.push_back(QPointF(curve.normPointList[i].x()-dx*0.5,
                                                    curve.normPointList[i].y()-dy*0.5));
            curve.bezierPointList.push_back(QPointF(curve.normPointList[i].x()+dx*0.5,
                                                    curve.normPointList[i].y()+dy*0.5));
        }
        curve.bezierPointList.push_back(curve.normPointList.back());
    }
}

double CustomChart::calCeilRange(double maxVal){

    double ynum = 0, temp = maxVal;
    while(temp/10 > 10){
        ynum ++;
        temp = temp / 10;
    }
    double ybase = std::pow(10, ynum-1);
    maxVal = std::ceil(maxVal / ybase) * ybase;
    return maxVal;
}

void CustomChart::clearFixedRange(){
    _isFixedMaxX = false;
    _isFixedMaxY = false;
    _isFixedMinX = false;
    _isFixedMinY = false;
}

void CustomChart::setFixedMaxX(double value){
    _isFixedMaxX = true;
    _fixedMaxX = value;
}
void CustomChart::setFixedMinX(double value){
    _isFixedMinX = true;
    _fixedMinX = value;
}
void CustomChart::setFixedMaxY(double value){
    _isFixedMaxY = true;
    _fixedMaxY = value;
}
void CustomChart::setFixedMinY(double value){
    _isFixedMinY = true;
    _fixedMinY = value;
}




